home *** CD-ROM | disk | FTP | other *** search
- /*
- * TERM286.C Copyright (C) 1992 Mark R. Nelson.
- *
- * This file, along with TERM286.H and REAL_ISR.C, make up a simple
- * terminal emulator that will run under the Phar Lap 286|DOS Extender.
- * This program demonstrates the use of a bimodal interrupt handler.
- * The protected mode interrupt is in this routine, the real mode
- * interrupt is found in REAL_ISR.C. The real mode interrupt is
- * linked into a DLL which is loaded at run time.
- */
-
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <ctype.h>
- #include <conio.h>
- #include <dos.h>
- #include "phapi.h"
- #include "term286.h"
-
- /*
- * The inline version of outp() for Turbo C will generate a warning
- * message under some circumstances. This turns off that message
- * by removing the macro the defines the inline version.
- */
- #ifdef __TURBOC__
- #undef outp
- #endif
-
- /*
- * These constants define the registers and bits used in setting
- * up the 8250 UART.
- */
- #define DIVISOR_LATCH_LSB 0
- #define DIVISOR_LATCH_MSB 1
- #define INTERRUPT_ENABLE_REGISTER 1
- #define IER_RECEIVE_DATA_INTERRUPT 0x01
- #define LINE_CONTROL_REGISTER 3
- #define LCR_NUMBER_OF_STOP_BITS 0x04
- #define LCR_PARITY_N 0x00
- #define LCR_PARITY_O 0x08
- #define LCR_PARITY_E 0x18
- #define LCR_DIVISOR_LATCH_ACCESS 0x80
- #define MODEM_CONTROL_REGISTER 4
- #define MCR_DATA_TERMINAL_READY 1
- #define MCR_REQUEST_TO_SEND 2
- #define MCR_OUT2 8
- #define LINE_STATUS_REGISTER 5
- #define LSR_THRE 0x20
-
- /*
- * The real mode ISR and the Port data structure are both found in the
- * real mode DLL. Because of this, they both have to be declared as
- * being far data.
- */
- extern struct port_data far Port;
- void far interrupt real_isr( void );
-
- /*
- * This is the protected mode ISR. It is identical to the real mode
- * ISR, except for the increment of the protected mode interrupt count
- * near the end. This routine reads in the character that caused the
- * interrupt, then tries to stuff it in the buffer and update the
- * head pointer. Finally, it increments the diagnostic counter,
- * outputs an EOI to the 8259 PIC, and exits.
- */
-
- void far interrupt prot_isr()
- {
- unsigned char c;
- int space_used;
-
- c = ( unsigned char ) inp( Port.uart_address );
- space_used = Port.head_pointer - Port.tail_pointer;
- if ( space_used < 0 )
- space_used += 1024;
- if ( space_used < 1023 ) {
- Port.buffer[ Port.head_pointer++ ] = c;
- Port.head_pointer &= 1023;
- }
- Port.prot_count++;
- outp( 0x20, 0x20 );
- }
-
- /*
- * This routine sets up the 4 data format parameters for and 8250
- * family UART. It also does a small amount of error checking, but
- * doesn't affect interrupts. It can be used before or after the
- * port has been opened.
- */
- int SetComParameters( int baud_rate,
- char parity,
- int word_length,
- int stop_bits )
- {
- int divisor;
- int lcr_out;
-
- if ( word_length < 5 || word_length > 8 )
- return( 0 );
- lcr_out = word_length - 5;
- switch ( toupper( parity ) ) {
- case 'N' :
- break;
- case 'O' :
- lcr_out |= LCR_PARITY_O;
- break;
- case 'E' :
- lcr_out |= LCR_PARITY_E;
- break;
- default :
- return( 0 );
- }
- switch ( stop_bits ) {
- case 1 :
- break;
- case 2 :
- lcr_out |= LCR_NUMBER_OF_STOP_BITS;
- break;
- default :
- return( 0 );
- }
- if ( baud_rate < 10 )
- return( 0 );
- divisor = ( int ) ( 115200L / baud_rate ) ;
- outp( Port.uart_address + LINE_CONTROL_REGISTER,
- LCR_DIVISOR_LATCH_ACCESS );
- outp( Port.uart_address + DIVISOR_LATCH_LSB, divisor & 0xff );
- outp( Port.uart_address + DIVISOR_LATCH_MSB, divisor >> 8 );
- outp( Port.uart_address + LINE_CONTROL_REGISTER, lcr_out );
- return( 1 );
- }
-
- /*
- * This routine is the one that actually sets up the interrupt
- * routines. It does this via several calls to Phar Lap 286
- * Extender routines.
- */
-
- void SetInterruptVectors( void )
- {
- REALPTR real_isr_ptr;
-
- Port.irq_mask = 1 << ( Port.interrupt_number % 8 );
- outp( Port.uart_address + INTERRUPT_ENABLE_REGISTER, 0 );
- real_isr_ptr = DosProtToReal( (PVOID) real_isr );
- if ( real_isr_ptr == 0 )
- exit( 1 );
- DosLockSegPages( SELECTOROF( real_isr ) );
- DosLockSegPages( SELECTOROF( &Port ) );
- DosSetRealProtVec( Port.interrupt_number,
- (PIHANDLER) prot_isr,
- real_isr_ptr,
- (PIHANDLER far *) &Port.old_prot_vector,
- (REALPTR far *) &Port.old_real_vector );
- }
-
- /*
- * This routine does everything necessary to open the port so the
- * main program can begin sending and receving characters. It sets
- * up the UART with the correct data format, then sets up the
- * interrupt service routines, and finally enables interrupts.
- * At that point the UART can now being really doing something.
- */
-
- enum port_names { COM1, COM2 };
-
- int OpenComPort( enum port_names port_name,
- unsigned int baud_rate,
- char parity,
- unsigned int word_length,
- unsigned int stop_bits )
- {
- int temp;
-
- switch ( port_name ) {
- case COM1 :
- Port.uart_address = 0x3f8;
- Port.interrupt_number = 12;
- break;
- case COM2 :
- Port.uart_address = 0x2f8;
- Port.interrupt_number = 1;;
- break;
- default :
- return 0;
- }
- Port.head_pointer = 0;
- Port.tail_pointer = 0;
- if ( ! SetComParameters( baud_rate, parity, word_length, stop_bits ) )
- return( 0 );
- SetInterruptVectors();
- /*
- * This section of code actually enables interrupts.
- */
- temp = inp( 0x21 );
- outp( 0x21, temp & ~Port.irq_mask );
- outp( Port.uart_address + MODEM_CONTROL_REGISTER,
- MCR_DATA_TERMINAL_READY + MCR_REQUEST_TO_SEND + MCR_OUT2 );
- outp( Port.uart_address + INTERRUPT_ENABLE_REGISTER,
- IER_RECEIVE_DATA_INTERRUPT );
- return 1;
- }
-
- /*
- * This short routine is used to send a character. All it does is wait
- * for the UART to be ready to accept the character, then stuff it
- * out the UART's transmit register.
- */
-
- void SendChar( int c )
- {
- int lsr;
-
- for ( ; ; ) {
- lsr = inp( Port.uart_address + LINE_STATUS_REGISTER );
- if ( lsr & LSR_THRE ) {
- outp( Port.uart_address, c );
- return;
- }
- }
- }
-
- /*
- * This boolean routine lets the main program know whether or not
- * characters are ready to be pulled out of the input buffer.
- */
-
- int DataReady( void )
- {
- return( Port.head_pointer != Port.tail_pointer );
- }
-
- /*
- * ReceiveChar reads in a single character from the input buffer, then
- * updates the tail pointer and returns the character.
- */
-
- int ReceiveChar( void )
- {
- int c;
-
- if ( Port.head_pointer == Port.tail_pointer )
- return( -1 );
- c = Port.buffer[ Port.tail_pointer++ ] & 0xff;
- Port.tail_pointer &= 1023;
- return( c );
- }
-
- /*
- * CloseComPort() disables interrupts, then restores the old interrupt
- * vectors and unlocks memory. It also drops DTR and CTS.
- */
- void CloseComPort( void )
- {
- int temp;
-
- outp( Port.uart_address + INTERRUPT_ENABLE_REGISTER, 0 );
- temp = inp( 0x21 );
- outp( 0x21, temp | Port.irq_mask );
- DosSetRealProtVec( Port.interrupt_number,
- (PIHANDLER) Port.old_port_vector,
- (REALPTR) Port.old_real_vector, 0, 0 );
- DosUnlockSegPages( SELECTOROF( real_isr ) );
- DosUnlockSegPages( SELECTOROF( &Port ) );
- outp( Port.uart_address + MODEM_CONTROL_REGISTER, 0 );
- }
-
- /*
- * The main program opens the port, then sits in a simple loop. The
- * loop just sends keystrokes out the com ports, and copies input
- * data to the screen. The only thing unusual is the provision for
- * printing out the port data if the input character is a ^Z.
- */
-
- main()
- {
- int c;
-
- if ( !OpenComPort( COM1, 2400, 'N', 8, 1 ) ) {
- printf( "Error opening port!\n" );
- return 1;
- }
- for ( ; ; ) {
- if ( kbhit() ) {
- c = getch();
- if ( c == 27 )
- break;
- else if ( c == 26 ) {
- printf( "\nPort status:\n" );
- printf( "UART address : %04.4x\n", Port.uart_address );
- printf( "Head pointer : %04.4x\n", Port.head_pointer );
- printf( "Tail pointer : %04.4x\n", Port.tail_pointer );
- printf( "Old prot vector : %08.8Fp\n", Port.old_prot_vector );
- printf( "Old real vector : %08.8Fp\n", Port.old_real_vector );
- printf( "IRQ mask : %02.2x\n", Port.irq_mask );
- printf( "Interrupt number : %02.2x\n", Port.interrupt_number );
- printf( "Real int count : %04.4x\n", Port.real_count );
- printf( "Prot int count : %04.4x\n", Port.prot_count );
- } else
- SendChar( c );
- }
- if ( DataReady() ) {
- c = ReceiveChar();
- putch( c );
- }
- }
- CloseComPort();
- return 0;
- }
-
-